#pragma once

#include <vector>
#include <math.h>
#include <string>
#include <thread>
#include <mutex>
#include <chrono>
#include <iomanip>
#include <gpiod.h>
#include "yj_return.hpp"
#include "spi_v1.hpp"

class pmw3901
{
public:
    typedef enum
    {
        pmw3901_reg_PRODUCT_ID = 0x00,           /**< product id register */
        pmw3901_reg_REVISION_ID = 0x01,          /**< revision id register */
        pmw3901_reg_MOTION = 0x02,               /**< motion register */
        pmw3901_reg_DELTA_X_L = 0x03,            /**< delta_x_l  register */
        pmw3901_reg_DELTA_X_H = 0x04,            /**< delta_x_h register */
        pmw3901_reg_DELTA_Y_L = 0x05,            /**< delta_y_l register */
        pmw3901_reg_DELTA_Y_H = 0x06,            /**< delta_y_h register */
        pmw3901_reg_SQUAL = 0x07,                /**< squal register */
        pmw3901_reg_RAW_DATA_SUM = 0x08,         /**< raw data sum register */
        pmw3901_reg_MAXIMUM_RAW_DATA = 0x09,     /**< maximum raw data register */
        pmw3901_reg_MINIMUM_RAW_DATA = 0x0A,     /**< minimum raw data register */
        pmw3901_reg_SHUTTER_LOWER = 0x0B,        /**< shutter lower register */
        pmw3901_reg_SHUTTER_UPPER = 0x0C,        /**< shutter upper register */
        pmw3901_reg_OBSERVATION = 0x15,          /**< observation register */
        pmw3901_reg_MOTION_BURST = 0x16,         /**< motion burst register */
        pmw3901_reg_POWER_UP_RESET = 0x3A,       /**< power up reset register */
        pmw3901_reg_SHUTDOWN = 0x3B,             /**< shutdown register */
        pmw3901_reg_RAW_DATA_GRAB = 0x58,        /**< raw data grab register */
        pmw3901_reg_RAW_DATA_GRAB_STATUS = 0x59, /**< raw data grab status register */
        pmw3901_reg_INVERSE_PRODUCT_ID = 0x5F,   /**< inverse product id register */

    } pmw3901_reg_en;

    typedef struct
    {
        int16_t delta_x;
        int16_t delta_y;
        yj_return flag;
    } pmw3901_motion_data_st;

    typedef struct
    {
        double x_move;
        double y_move;
    } pmw3901_move_data_st;

private:
    spi_v1 *_spi; // SPI最大2MHZ
    std::mutex _data_lock;

    double _unread_x_move;
    double _unread_y_move;

    uint32_t _filter_time; // 滤波次数，实际移动距离为该次数下读取相加计算

    struct gpiod_chip *_gpioChip_p;
    struct gpiod_line *_deLine;
    std::string _gpioChip;
    uint32_t _dePinOffset;

    yj_return _init_flag;
    yj_return _init_reset_pin();
    yj_return _deinit_reset_pin();
    void _reset();

public:
    pmw3901(spi_v1 *spi, std::string gpioChip, uint32_t dePinOffset);
    ~pmw3901();
    yj_return init();
    yj_return burst_read_motion(pmw3901_motion_data_st &p_motion);
    yj_return count_shift_with_height(double height); // height mm
    yj_return read_move(pmw3901_move_data_st &move_data);
    yj_return read_id();
};
